package com.gzxx.service.impl;

import com.alibaba.druid.util.StringUtils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gzxx.constant.SystemConstant;
import com.gzxx.domain.bo.SysMenuBO;
import com.gzxx.domain.po.SysMenu;
import com.gzxx.domain.vo.SysMenuVo;
import com.gzxx.exception.ServiceException;
import com.gzxx.mapper.SysMenuMapper;
import com.gzxx.mapper.SysRoleMapper;
import com.gzxx.service.SysMenuService;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author pengpdx
 * @Date 2020/7/24 12:05
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Transactional(readOnly = true, rollbackFor = Exception.class, timeout = 5)
public class SysMenuServiceImpl implements SysMenuService {

    private final SysMenuMapper sysMenuMapper;
    private final SysRoleMapper sysRoleMapper;

    /**
     * 新增菜单
     *
     * @param sysMenuBO 业务实体
     * @return
     */
    @Transactional(rollbackFor = Exception.class, timeout = 5)
    @Override
    public boolean add(SysMenuBO sysMenuBO) {
        SysMenu persist = sysMenuBO.persist();
        return sysMenuMapper.insert(persist) > 0;
    }

    /**
     * 根据用户获取相关菜单
     *
     * @param ids 角色标识
     * @return
     */
    @Transactional(rollbackFor = Exception.class, timeout = 5)
    @Override
    public List<String> getMenuPermsByRoleIds(@NonNull List<Long> ids) {
        return sysMenuMapper.getMenuPermsByRoleIds(ids);
    }

    /**
     * 删除菜单
     *
     * @param id 菜单ID
     * @return
     */
    @Transactional(rollbackFor = Exception.class, timeout = 5)
    @Override
    public boolean delete(@NonNull Long id) {
        return sysMenuMapper.deleteById(id) > 0;
    }

    /**
     * 修改菜单
     *
     * @param sysMenuBO
     * @return
     */
    @Transactional(rollbackFor = Exception.class, timeout = 5)
    @Override
    public boolean update(SysMenuBO sysMenuBO) {
        SysMenu sysMenu = sysMenuBO.edit();
        return sysMenuMapper.updateById(sysMenu) > 0;
    }

    /**
     * 根据ID查询
     *
     * @param id
     * @return
     */
    @Override
    public SysMenuVo getSysMenuById(@NonNull Long id) {
        SysMenuVo sysMenuVo = sysMenuMapper.getSysMenuById(id);
        //获取父级名称
        SysMenuVo parentSysMenuVo = sysMenuMapper.getSysMenuById(sysMenuVo.getParentId());
        if (parentSysMenuVo != null) {
            sysMenuVo.setParentName(parentSysMenuVo.getMenuName());
        }
        return sysMenuVo;
    }

    /**
     * 根据条件查询
     *
     * @param sysMenuBO
     * @param nowPage
     * @param pageShow
     * @return
     */
    @Override
    public IPage<SysMenuVo> querySysMenus(SysMenuBO sysMenuBO, int nowPage, int pageShow) {
        try {
            Map<?, ?> queryParams = sysMenuBO.queryParams();
            Page<SysMenuVo> page = new Page<SysMenuVo>(nowPage, pageShow);
            return sysMenuMapper.querySysMenus(page, queryParams);
        } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            throw new ServiceException("class:SysMenuServiceImpl method:menus exception", e);
        }
    }

    /**
     * 根据父ID获取子目录列表
     *
     * @param parentId
     * @return
     */
    @Override
    public List<SysMenuVo> queryListByParentId(@NonNull Long parentId) {
        return sysMenuMapper.queryListByParentId(parentId);
    }

    /**
     * 获取父目录下指定ID目录
     *
     * @param parentId
     * @param menuIdList
     * @return
     */
    @Override
    public List<SysMenuVo> queryListByParentId(@NonNull Long parentId, List<Long> menuIdList) {
        List<SysMenuVo> menuList = queryListByParentId(parentId);
        if (menuIdList == null) {
            return menuList;
        }

        List<SysMenuVo> userMenuList = new ArrayList<>();
        for (SysMenuVo menu : menuList) {
            if (menuIdList.contains(menu.getId())) {
                userMenuList.add(menu);
            }
        }
        return userMenuList;
    }


    @Override
    public List<SysMenuVo> getUserMenuList(Long userId) {
        //用户菜单列表
        List<Long> menuIdList = sysRoleMapper.queryAllMenuId(userId);
        return this.getAllMenuList(menuIdList);
    }

    @Override
    public List<SysMenuVo> getAllSysMenuList(Integer type) {
        List<SysMenuVo> menuList = sysMenuMapper.queryAllMenuList(type);
        List<SysMenuVo> oneMenuList = menuList.stream().filter(item -> item.getParentId() == 0).collect(Collectors.toList());

        oneMenuList.stream().forEach(oneMenu -> {

            List<SysMenuVo> twoMenuList = menuList.stream().filter(twoItem ->
                    StringUtils.equals(String.valueOf(twoItem.getParentId()), String.valueOf(oneMenu.getId())))
                    .collect(Collectors.toList());

            twoMenuList.stream().forEach(twoItem -> {
                List<SysMenuVo> threeMenuList = menuList.stream().filter(threeItem ->
                        StringUtils.equals(String.valueOf(threeItem.getParentId()), String.valueOf(twoItem.getId())))
                        .collect(Collectors.toList());
                twoItem.setList(threeMenuList);
            });
            oneMenu.setList(twoMenuList);
        });
        return oneMenuList;
    }

    @Override
    public SysMenuVo getSysMenuByName(@NonNull String menuName) {
        return sysMenuMapper.getSysMenuByName(menuName);
    }

    /**
     * 获取所有父级id
     */
    @Override
    public List<Long> getParentAll() {
        return sysMenuMapper.queryParentAll();
    }


    /**
     * 获取所有菜单列表
     *
     * @param menuIdList
     * @return
     */
    private List<SysMenuVo> getAllMenuList(List<Long> menuIdList) {
        //查询root目录列表
        List<SysMenuVo> menuList = this.queryListByParentId(0L, menuIdList);
        //递归获取子菜单
        this.getMenuTreeList(menuList, menuIdList);
        return menuList;
    }

    /**
     * 递归获取子菜单
     *
     * @param menuList
     * @param menuIdList
     * @return
     */
    private List<SysMenuVo> getMenuTreeList(List<SysMenuVo> menuList, List<Long> menuIdList) {
        List<SysMenuVo> subMenuList = new ArrayList<SysMenuVo>();
        for (SysMenuVo entity : menuList) {
            //目录
            if (entity.getMenuType() == SystemConstant.MenuType.CATALOG.getValue()) {
                entity.setList(this.getMenuTreeList(this.queryListByParentId(entity.getId(), menuIdList), menuIdList));
            }
            subMenuList.add(entity);
        }
        return subMenuList;
    }


}
